using System;
using System.Collections.Generic;
using Mono.CSharp;
using System.Text;

namespace armcontrolgui
{
	public abstract class ArmController
	{
		public delegate void ArmDelegate(ArmController Sender);
		public abstract event ArmDelegate PositionUpdated;
		
		public static Dictionary<Guid, ArmController> ControllerContext = new Dictionary<Guid, ArmController>();
		
		protected Guid Id;
		
		public ArmController()
		{
			this.Id = Guid.NewGuid();
			ControllerContext.Add(this.Id, this);
		}
		
		public virtual void GoHome()
		{
			foreach (Axis AxisItem in AxisList) {
				AxisItem.Position = AxisItem.Center;
			}
		}
		
		/// <summary>
		/// List of all axis.
		/// </summary>
		public abstract List<Axis> AxisList { get; }
		
		/// <summary>
		/// Window to setup the arm.
		/// </summary>
		public abstract Gtk.Window ArmSetup { get; }
		
		/// <summary>
		/// List of view of the arm.
		/// </summary>
		public abstract List<Gtk.Widget> Views { get; }
		
		/// <summary>
		/// A widget displaying all the additional info of the device.
		/// </summary>
		public abstract Gtk.Widget AdditionalInfoWidget { get; }
		
		public Axis this[string Index] {
			get {
				foreach (Axis AxisItem in this.AxisList) {
					if(AxisItem.Name == Index)
						return AxisItem;
				}
				return null;
			}
		}
		
		public Axis this[int Index] {
			get {
				foreach (Axis AxisItem in this.AxisList) {
					if(AxisItem.Index == Index)
						return AxisItem;
				}
				return null;
			}
		}
		
		public virtual string Header()
		{
			StringBuilder Builder = new StringBuilder();
			
			Builder.AppendLine("ArmController Arm;");
			Builder.Append("if (!ArmController.ControllerContext.TryGetValue(new Guid(\"");
			Builder.Append(this.Id.ToString());
			Builder.AppendLine("\"), out Arm))");
			Builder.AppendLine("	throw new KeyNotFoundException(\"Arm id not found\");");
			
			return Builder.ToString();
		}
		
		public System.Threading.Thread ScriptRun(string Script)
		{
			Evaluator.Init(new string[0]);
			
			Evaluator.ReferenceAssembly(typeof(ArmController).Assembly);
			
			Evaluator.Run("using System;");
			Evaluator.Run("using System.Collections.Generic;");
			Evaluator.Run("using System.Linq;");
			Evaluator.Run("using armcontrolgui;");
			Evaluator.Run("using System.Threading;");
			
			CompiledMethod Method = Evaluator.Compile(this.Header() + Script);
			
			return RunOnThread(()=>{
				object Ret = null;
				Method.Invoke(ref Ret);
			}, "ScriptRun");
			
		}
		
		private static System.Threading.Thread RunOnThread (RunGtkThread.VoidDelegate MyDelegate, string ThreadName)
		{
			System.Threading.Thread newThread = new System.Threading.Thread (() => {
				SafeCall(MyDelegate).Invoke();
			});
			
			newThread.IsBackground = true;
			newThread.Name = ThreadName;
			newThread.Start ();
			return newThread;
		}
		
		private static RunGtkThread.VoidDelegate SafeCall(RunGtkThread.VoidDelegate MyDelegate)
		{
			return delegate {
				try {
					MyDelegate ();
				} catch (Exception e) {
					Console.WriteLine("ScriptEngine: {0}", e);
				}
			};
		}
		
	}
}
